#ifndef _WINDOWX11_H_
#define _WINDOWX11_H_

#include <stdlib.h>

template <int n> void magical_strcpy( char (&dest)[n], const char src[] )
{
  unsigned int i = 0;
  while ( i < n - 1 )
  {
    if ( src[i] == 0 )
      break;
    dest[i] = src[i];
    i++;
  }
  dest[i] = 0;
}

template <typename T>
class DirtyVector
{
public:
  explicit DirtyVector(size_t size = 0)
  {
    data_ = size == 0 ? NULL : (static_cast<T*>(malloc(size * sizeof(T))));
  }
  ~DirtyVector()
  {
    if (data_!=NULL)
    {
      free(data_);
      data_ = NULL;
    }
  }
  void reset(size_t size = 0)
  {
    DirtyVector<T> temp(size);
    swap(temp);
  }
  T& operator[](size_t i)
  {
    assert(data_);
    return data_[i];
  }
  T* get()
  {
    return data_;
  }
  bool isEmpty() const
  {
    return data_ == NULL;
  }
  void swap(DirtyVector& other)
  {
    T* temp = data_;
    data_ = other.data_;
    other.data_ = temp;
  }
private:
  T* data_;
};

class Context;

class WindowX11: public WindowInterface
{
public:
  ~WindowX11();

  bool open(Context* context, InputListener* listener, const char title[], int width, int height );
  void close();

  // show the window (it is initially hidden)

  void show();

  // hide the window
  void hide();

  // check if window is visible?

  bool visible() const;

  // put window in fullscreen mode

  void fullscreen(int width, int height);

  // put window in windowed mode

  void windowed( int width, int height );

  // center the window on the desktop
  // note: has no effect if the window is minimized or maximized

  void center();

  // zoom window

  void zoom( float scale );

  bool isRun() const;

  void update();

  // get the window handle.
  // null if the window failed to initialize.

  WindowHandle handle() const;

  int getWidth() const;
  int getHeight() const;
  bool getActive() const;

  Mode getOutputMode() const;

  // title management
  void title(const char title[]);

  // listener management
  InputListener * listener() const;

  enum
  {
    eventMask_ = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ButtonMotionMask,
    keyMapSize_ = 256
  };

  typedef DirtyVector<char> TBuffer;
  typedef Key::Code TKeyMap[keyMapSize_];
  typedef bool TKeyFlags[keyMapSize_];

protected:
  void _close();

private:
  void pumpEvents();

  void handleEvent(const ::XEvent& event);


  static bool initializeKeyMaps();


  // X11 variables
  Window				x11Window;
  Display*			x11Display;
  long				x11Screen;
  XVisualInfo*		x11Visual;
  Colormap			x11Colormap;

  Window					sRootWindow;
  XSetWindowAttributes	sWA;
  unsigned int			ui32Mask;
  int						i32Depth;
  Atom wmProtocols_;
  Atom wmDeleteWindow_;

  TBuffer buffer_;
  bool isShuttingDown_;

  char _title[256];
  int _width;
  int _height;
  bool _open;

  Mode mode;

  static TKeyMap normalKeys_;
  static TKeyMap functionKeys_;
  static TKeyFlags keyIsPressed_;
  static TKeyFlags keyIsReleased_;
  static bool keyMapsInitialized_;

  Context * context;		// the context interface (must not be null)
  InputListener * _listener;			// the listener interface (may be null)
};


typedef WindowX11 WindowClass;

#endif  // _WINDOWX11_H_
